#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File  : menu.py
# @Author: shadow
# @Date  : 2019/12/3
# @Desc  : menu page

from tkinter import *
import tkinter.messagebox as ma
from tkinter import ttk
import userdata as userdata
import hashlib
from PIL import Image, ImageTk

TAKE = 1
SAVE = 2
TRANSFER = 3
SHOWINFO = 4
INPUT = 5

CHANGE = 6
VIEW = 7


# 输入数字检查，需要是数字
def num_check(content: str):
    if content.isdigit():
        return True
    else:
        return False


# 用户信息类，用与用户的存取款信息更新
class MenuInfo(object):
    def __init__(self, user):
        """
        :param user: 命名元组， num, name, passwd, balance, telephone
        """
        self.info = user._asdict()  # 返回有序字典

    def get_info(self):
        ma.showinfo("MenuPage", f"username:{self.name}, num:{self.num} balance:{self.balance}")

    # 存款处理
    def money_save(self, num: int):
        self.info['balance'] = int(self.info['balance']) + num
        if userdata.change_balance(self.info):
            ma.showinfo("SAVE", f"SUCESS:\n  存入：{num} \n  余额：{self.info['balance']}")
            return True

    # 取款处理
    def money_take(self, num: int, show=1):
        """
        :param num: the num of take money
        :param show: 0: not show messagebox 1: show massage if take sucess
        :return: True if take sucess ,otherwise False
        """
        if not num:
            ma.showwarning("TAKE", "Error num input! ")
            return False
        balence = int(self.info['balance'])
        if balence >= num:
            self.info['balance'] = balence - num
            if userdata.change_balance(self.info) and show:
                ma.showinfo("TAKE", f"SUCESS:\n  取出：{num} \n  余额：{self.info['balance']}")
            return True
        else:
            # ma.showwarning("TAKE", "You have no enough money! ")
            return False

    # 转账处理
    def money_trans(self, user, option, num: int):
        user_info = userdata.find_user(user, option)    # 获取转入账户信息，返回元素有序字典
        if user_info:    # 转入账户存在
            if user_info["name"] == self.info["name"]:
                ma.showwarning("TRANSFER", "不能转账给自己! ")
                return False
            if self.money_take(num, show=0):  # 账户余额足够
                # print(__name__, "money_trans:", user_info)
                user_info["balance"] = int(user_info["balance"])+num
                if userdata.change_balance(user_info):
                    ma.showinfo("TRANSFER", f"SUCESS:\n  {self.info['name']}  转账给 {user_info['name']}\n  金额：{num}")
            else:   # 余额不足
                ma.showwarning("Warning", "余额不足!")
                return False
        else:
            ma.showwarning("Warning", "No this user,pleasr ensure it!")
            return False
        return True


# 功能界面类
class MenuPage(object):
    def __init__(self, user, admin=False, window=None):
        self.window = window
        self.admin = admin
        self.window.geometry("400x200")
        # self.window.wm_resizable(False, False)  # 禁止修改长宽
        self.user = MenuInfo(user)
        self.page = Frame(self.window)
        self.value = IntVar()
        self.input = StringVar()    # 数据
        self.userinfo = StringVar()  # 用户信息
        self.prompt = StringVar()   # 提示信息
        self.bgcolor = ""
        self.state = []
        self.cmd = self.window.register(num_check)
        self.page_init()
        # self.img = PhotoImage(file=r'../image/atm.gif', width=100, height=100)  # 仅支持gif图片
        self.img = ImageTk.PhotoImage(Image.open("../image/atm.jpg").resize((88, 100), Image.ANTIALIAS))
        self.select_page()

    # 属性初始化
    def page_init(self):
        self.input.set("")
        self.userinfo.set('')
        self.prompt.set("")
        self.bgcolor = None     # None表示没有背景色，也可以使用#加rgb颜色值设置颜色如： #FFFFFF
        self.state = [NORMAL, NORMAL, NORMAL, DISABLED]

    # 刷新界面，重绘框架，多次被调用，写成装饰器函数
    def new_frame(func):
        def wrapper(*args, **kwargs):
            args[0].page.destroy()
            args[0].page = Frame(args[0].window)
            args[0].page.pack()  # pack(side=LEFT,anchor=N)
            return func(*args, **kwargs)
        return wrapper  # 返回

    # 选择功能界面，管理员页面和普通客户页面是不一样的
    @new_frame
    def select_page(self):
        self.window.title("ATM-MENU-SELECT")
        if self.admin:  # 管理员账户页面
            lable = ["修改/删除", "查找/显示", "退出"]
            menutop = Menu(self.page)    # 创建顶层菜单
            # menuchange = Menu(menutop, tearoff=0)   # 添加子菜单change
            # menushow = Menu(menutop, tearoff=0)  # 添加子菜单show
            menutop.add_command(label=lable[0], command=self.change_page)  # 在子菜单中添加功能
            menutop.add_command(label=lable[1], command=self.view_page)
            menutop.add_command(label=lable[2], command=self.window.quit)
            msg_info = '''使用说明：
1. 修改/删除：
    修改：使用用户名来修改用户名和密码
    删除：使用用户名来删除用户
2. 查找/显示：
    查找：使用用户名或账号来获取用户信息
    显示：列出所有用户的大概信息
3. 退出：退出并关闭应用
            '''
            Message(self.page, text=msg_info, bg="lightgreen").grid(stick=W)
            self.window.config(menu=menutop)
        else:
            Label(self.page, text="请选择一项:").grid(row=0, column=0, stick=W)
            Label(self.page, image=self.img).grid(row=1, rowspan=4, stick=W)
            Radiobutton(self.page, text="取款", variable=self.value, value=TAKE).grid(row=1, column=1, padx=8)
            Radiobutton(self.page, text="存款", variable=self.value, value=SAVE).grid(row=2, column=1, padx=8)
            Radiobutton(self.page, text="转账", variable=self.value, value=TRANSFER).grid(row=3, column=1, padx=8)
            Radiobutton(self.page, text="查询", variable=self.value, value=SHOWINFO).grid(row=4, column=1, padx=8)

            Button(self.page, text="确定", bg="green", width=10, height=2, command=self.select)\
                .grid(row=1, rowspan=4, column=2, padx=20)
            Button(self.page, text="退出", bg="red", width=10, command=self.page.quit).grid(row=5, column=2, stick=E)

    # 取款界面
    @new_frame
    def take_page(self):
        self.window.title("ATM-MENU-TAKE")

        Label(self.page, height=2, text=f"用户：{self.user.info['name']}").grid(row=0)
        Label(self.page, bg=self.bgcolor, textvariable=self.prompt).grid(row=1, column=1, columnspan=2, stick=W)
        Label(self.page, height=2, text="请输入取款金额:").grid(row=2, stick=W)
        ent = (Entry(self.page, width=10, textvariable=self.input, validate='key', validatecommand=(self.cmd, '%P'),
              invalidcommand=lambda: self.refresh(1)))
        ent.grid(row=2, column=1, stick=W)
        Button(self.page, text="取款", width=8, bg="lime", command=lambda: self.todo(TAKE)).grid(row=2, column=2, padx=10)
        Button(self.page, height=2, bg="blue", text="返回", width=8, command=self.refresh).grid(row=3, pady=15)
        Button(self.page, height=2, bg="red", text="退出", width=8, command=self.page.quit).grid(row=3, column=4)
        ent.focus_set()

    # 存款界面
    @new_frame
    def save_page(self):
        self.window.title("ATM-MENU-SAVE")

        Label(self.page, height=2, text=f"用户：{self.user.info['name']}").grid(row=0)
        Label(self.page, bg=self.bgcolor, textvariable=self.prompt).grid(row=1, column=1, columnspan=2, stick=W)
        Label(self.page, height=2, text="请输入存款金额:").grid(row=2, stick=W)
        ent = Entry(self.page, width=10, textvariable=self.input, validate='key', validatecommand=(self.cmd, '%P'),
              invalidcommand=lambda: self.refresh(2))
        ent.grid(row=2, column=1, stick=W)
        Button(self.page, width=8, text="存款", bg="lime", command=lambda: self.todo(SAVE)).grid(row=2, column=2, padx=10)
        Button(self.page, height=2, text="返回", bg="blue", width=8, command=self.refresh).grid(row=3, pady=15)
        Button(self.page, height=2, text="退出", bg="red", width=8, command=self.page.quit).grid(row=3, column=4)
        ent.focus_set()

    # 转账界面
    @new_frame
    def transfer_page(self, ent=0):
        self.window.title("ATM-MENU-TRANSFER")

        if ent == 0:
            self.bgcolor = "yellow"
            self.prompt.set("请输入账户信息,按回车确认")
            self.value.set(1)

        Label(self.page, height=2, text=f"用户：{self.user.info['name']}").grid(row=0, stick=W)
        Label(self.page, bg=self.bgcolor, textvariable=self.prompt).grid(row=1, column=2, columnspan=2, stick=W)
        Label(self.page, text="请输入要转入账户和金额:").grid(row=1, column=0, columnspan=2, stick=W)
        Radiobutton(self.page, text="用户名转账",state=self.state[0],  variable=self.value, value=1).grid(row=2, stick=W)
        Radiobutton(self.page, text="账号转账",state=self.state[1],  variable=self.value, value=0).grid(row=3, stick=W)
        Label(self.page, text="账户:").grid(row=2, column=1, stick=W)
        entry = Entry(self.page, width=10, state=self.state[2], textvariable=self.userinfo)
        entry.grid(row=2, column=2, stick=W)
        Label(self.page, text="金额:").grid(row=3, column=1, stick=W)
        Entry(self.page, width=10, textvariable=self.input, state=self.state[3], validate='key',
              validatecommand=(self.cmd, '%P'), invalidcommand=lambda: self.refresh(3)).grid(row=3, column=2, stick=W)
        Button(self.page, height=2, bg="lime", text="转账", width=8, command=lambda: self.todo(TRANSFER)
               ).grid(row=2, rowspan=2, column=3, padx=30)
        Button(self.page, height=2, bg="blue", text="返回", width=10, command=self.refresh).grid(row=4, pady=5)
        Button(self.page, height=2, bg="red", text="退出", width=10, command=self.page.quit).grid(row=4, column=3)
        if ent < 2:
            entry.bind("<Return>", lambda x: self.refresh(5))
            entry.focus_set()

    # 查询信息界面
    @new_frame
    def info_page(self, userInfo=None):
        self.window.title("ATM-MENU-INFO")
        if not userInfo:
            userInfo = self.user.info

        Label(self.page, text="用户信息：").grid(row=0, stick=W)
        Label(self.page, image=self.img).grid(row=1, rowspan=4, stick=W)  # 图片显示不出来, 图片对象需要是全局变量
        Label(self.page, text=f"用户：{userInfo['name']}").grid(row=1, column=1, stick=W)
        Label(self.page, text=f"账号：{userInfo['num']}").grid(row=2, column=1, stick=W)
        Label(self.page, text=f"电话：{userInfo['telephone'][:-1]}").grid(row=3, column=1, stick=W)  # 去掉换行符
        Label(self.page, text=f"余额：{userInfo['balance']}").grid(row=4, column=1, stick=W)
        Button(self.page, height=2, bg="blue", text="返回", width=10, command=self.refresh).grid(row=5, pady=10)
        Button(self.page, height=2, bg="red", text="退出", width=10, command=self.page.quit).grid(row=5, column=2)

    # 用户信息修改
    @new_frame
    def change_page(self, ent=0):
        self.window.title("ATM-MENU-CHANGE")

        if ent == 0:    # 初始化
            self.bgcolor = "yellow"
            self.prompt.set("请输入用户名")
            msg = "请输入新的用户名"
        if ent == 1:
            msg = "请输入新的密码"


        Label(self.page, text="请选择功能").grid(row=2)
        self.comb = ttk.Combobox(self.page, width=9)
        self.comb["values"] = ("修改用户名", "修改密码", "删除用户")
        self.comb.current(ent)
        self.comb.grid(row=3, rowspan=2, padx=5)
        self.comb.bind('<<ComboboxSelected>>', lambda x: self.change_page(self.comb.current()))  # 绑定选择事件

        if ent == 2:
            Label(self.page).grid(row=1, column=1)
            Label(self.page, bg=self.bgcolor, textvariable=self.prompt).grid(row=2, column=1, stick=W)
            Entry(self.page, width=15, textvariable=self.input).grid(row=3, column=1, pady=5, stick=W)
            Label(self.page).grid(row=4, column=1)
        else:
            Label(self.page, bg=self.bgcolor, textvariable=self.prompt).grid(row=1, column=1, stick=W)
            Entry(self.page, width=15, textvariable=self.input).grid(row=2, column=1, stick=W)
            Label(self.page, bg=self.bgcolor, text=msg).grid(row=3, column=1, pady=5, stick=W)
            Entry(self.page, width=15, textvariable=self.userinfo).grid(row=4, column=1, stick=W)

        Button(self.page, height=2, bg="lime", text="执行", width=8, command=self.change).grid(row=1, rowspan=4, column=2, padx=5)
        Button(self.page, height=2, bg="blue", text="返回", width=10, command=self.refresh).grid(row=5, pady=5)
        Button(self.page, height=2, bg="red", text="退出", width=10, command=self.page.quit).grid(row=5, column=2)

    # 用户信息查找/展示
    @new_frame
    def view_page(self, ent=0):
        self.window.title("ATM-MENU-VIEW")

        if ent == 0:
            self.bgcolor = "yellow"
            self.prompt.set("请输入账户名")
            self.value.set(1)
        Label(self.page).grid()
        Radiobutton(self.page, text="使用账号查找", variable=self.value, value=1,
                    command=lambda: self.prompt.set("请输入用户账号")).grid(row=1, stick=W)
        Radiobutton(self.page, text="使用用户名查找", variable=self.value, value=2,
                    command=lambda: self.prompt.set("请输入用户名")).grid(row=2, stick=W)
        Radiobutton(self.page, text="所有用户展示", variable=self.value, value=3,
                    command=lambda: self.prompt.set("请点击展示按钮")).grid(row=3, stick=W)
        Label(self.page, bg=self.bgcolor, textvariable=self.prompt).grid(row=1, column=2, stick=W)
        Entry(self.page, width=15, state=self.state[0], textvariable=self.userinfo).grid(row=2, column=2, stick=W)
        Button(self.page, height=2, bg="lime", text="展示", width=8, command=self.view)\
            .grid(row=2, rowspan=2, column=3, padx=5)
        Button(self.page, height=2, bg="blue", text="返回", width=10, command=self.refresh).grid(row=4, pady=5)
        Button(self.page, height=2, bg="red", text="退出", width=10, command=self.page.quit).grid(row=4, column=3)

    # 列出所有用户信息，使用tree_table
    @new_frame
    def all_page(self, users):
        self.window.title("ATM-MENU-VIEW")
        tree_num = 0

        tree_table = ttk.Treeview(self.page, height=6, show="headings")    # 隐藏第一列
        ybar = ttk.Scrollbar(self.page, orient=VERTICAL, command=tree_table.yview)  # 滚动条绑定treetable的Y向
        # columns = {"NUM": 60, "NAME": 100, "BALANCE": 80, "TELEPHONE": 120}
        columns = {"账号": 60, "用户名": 100, "余额": 80, "电话号码": 120}  # 标题列名和宽度
        tree_table["columns"] = list(columns.keys())
        for key, value in columns.items():
            tree_table.column(key, width=value)
            tree_table.heading(key, text=key)

        for user in users:
            tree_num += 1
            tmp = [user[0], user[1], user[3], user[4]]  # 取出账号，用户名，余额和电话
            tree_table.insert("", tree_num, values=tmp)  # 插入一行信息

        if tree_num > 6:
            tree_table.configure(yscrollcommand=ybar.set)

        tree_table.grid(row=0, rowspan=5, column=0, columnspan=5)
        ybar.grid(row=0, rowspan=5, column=5, sticky=NS)    # 设置滚动条高度南北朝向
        Button(self.page, bg="blue", text="返回", width=10, command=self.view_page).grid(row=5, pady=10)
        Button(self.page, bg="red", text="退出", width=10, command=self.page.quit).grid(row=5, column=4, stick=E)

    # 刷新页面, 默认返回到主页面
    def refresh(self, ent=0):
        if ent:   # 输入信息不符合要求 1：取款 2：存款 3：转账 4：信息 5:输入限制
            if ent == TAKE:
                self.bgcolor = "red"
                self.prompt.set("请输入数字")
                self.take_page()
            elif ent == SAVE:
                self.bgcolor = "red"
                self.prompt.set("请输入数字")
                self.save_page()
            elif ent == TRANSFER:
                self.bgcolor = "red"
                self.prompt.set("请输入数字")
                self.transfer_page(1)
            elif ent == INPUT:
                self.state = [DISABLED, DISABLED, "readonly", NORMAL]
                self.prompt.set("请输入转账金额后按回车确认")
                self.transfer_page(2)
            else:
                ma.showwarning("Warning", "输入错误警告！")
        else:   # 返回主界面，清空所有输入信息
            self.page_init()
            self.select_page()

    # 点击按钮执行对应操作
    def todo(self, ent):
        num = self.input.get()
        if not num.isdigit():
            ma.showwarning("Warning", "请先输入金额！")
            return False
        num = int(num)

        if ent == TAKE:
            if num % 50 != 0:  # 最小面值50
                self.bgcolor = "red"
                self.prompt.set("取款失败: 金额要是50倍数")
            else:
                if self.user.money_take(num):
                    self.bgcolor = "green"
                    self.prompt.set("取款成功,可输入数字继续")
                else:
                    self.bgcolor = "red"
                    self.prompt.set("取款失败: 余额不足")
            self.take_page()
        elif ent == SAVE:
            self.user.money_save(num)
            self.bgcolor = "green"
            self.prompt.set("存款成功,可输入数字继续")
            self.save_page()
        elif ent == TRANSFER:
            if self.user.money_trans(self.userinfo.get(), self.value.get(), num):  # 转账成功，返回操作界面
                self.refresh()
            else:   # 转账失败，重新操作
                self.page_init()
                self.transfer_page()

        self.input.set("")

    # 修改用户名和密码，简单操作，没有做深入规则判断
    def change(self):
        comb = self.comb.current()
        input = self.input.get()
        changeinfo = self.userinfo.get()

        user = userdata.find_user(input)
        print(user)
        if user:
            if comb == 0:  # "修改用户名":
                user["name"] = changeinfo
            elif comb == 1:  # "修改密码":
                md5 = hashlib.md5()
                md5.update(changeinfo.encode("utf8"))
                pwd_md5 = md5.hexdigest()
                user["passwd"] = pwd_md5
            elif comb == 2:  # "删除用户":
                user["flag"] = 0
            userinfo = ",".join('%s' %i for i in user.values())
            print(userinfo)
            userdata.change_info(userinfo)
        else:
            ma.showwarning("Warning", f"用户{input}不存在")

    # 查找用户信息
    def view(self):
        option = self.value.get()
        info = self.userinfo.get()
        if option < 3:  # 用户名搜索 账号搜索 显示全部
            user_info = userdata.find_user(info, option-1)
            if user_info:
                self.info_page(user_info)
            else:
                self.bgcolor = "red"
                self.prompt.set("没找到对应用户信息")
                self.view_page(1)
        else:
            self.all_page(userdata.get_all())

    # 选择功能处理
    def select(self):
        option = self.value.get()
        if option:
            if option == TAKE:
                self.take_page()
            elif option == SAVE:
                self.save_page()
            elif option == TRANSFER:
                self.transfer_page()
            elif option == SHOWINFO:
                self.info_page()
            elif option == CHANGE:
                self.change_page()
            elif option == VIEW:
                self.view_page()
            else:
                ma.showinfo("Prompt", "Please select an option! ")

